package hasthi.metamodel;

import static hasthi.common.constants.HasthiConstants.GET_RESOURCES_ACTION;
import static hasthi.common.constants.HasthiConstants.GET_RESOURCES_HOLDER_ACTION;
import static hasthi.common.constants.HasthiConstants.LOGGER_NAME;
import static hasthi.common.constants.WSDMConstants.GROUP_PARAM;
import static hasthi.common.constants.WSDMConstants.HOSTNAME_PARAM;
import static hasthi.common.constants.WSDMConstants.RESOURCE_CATEGORY_PARAM;
import static hasthi.common.constants.WSDMConstants.RESOURCE_STATUS_PARAM;
import static hasthi.common.constants.WSDMConstants.RESOURCE_TYPE_PARAM;
import hasthi.common.HasthiError;
import hasthi.common.HasthiException;
import hasthi.common.InvaliedResourceDataException;
import hasthi.common.XmlBeanUtils;
import hasthi.common.HasthiException.FaultCode;
import hasthi.common.constants.WsrfConstants;
import hasthi.container.MessageContext;
import hasthi.container.NodeAddress;
import hasthi.container.SimpleMessageContext;
import hasthi.container.UnicastContianier;
import hasthi.manager.GetResourceHoldersDocument;
import hasthi.manager.GetResourceHoldersResponseDocument;
import hasthi.manager.GetResourcesDocument;
import hasthi.manager.GetResourcesResponseDocument;
import hasthi.manager.ManagedResourceType;
import hasthi.manager.ManagerAddress;
import hasthi.manager.ManagerClientUtils;
import hasthi.manager.GetResourceHoldersDocument.GetResourceHolders;
import hasthi.metamodel.resource.ManagedResource;
import hasthi.metamodel.resource.ResourceModelContext;
import hasthi.wsrf.WsrfClientUtils;

import java.util.Map;

import javax.xml.namespace.QName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;

import wsrf.GetResourcePropertyDocumentDocument1;
import wsrf.GetResourcePropertyDocumentResponseDocument;

public class ResourceUtils {
    private static Log log = LogFactory.getLog(LOGGER_NAME);
    
    
    /**
     * Given the management agent of a resource, this method build the meta-object for the resource.
     * @param managementEprOfResource
     * @param container
     * @param resourceModel
     * @return
     * @throws HasthiException
     */
    public static ManagedResource createProxy4Resource(String managementEprOfResource, UnicastContianier container,
            MixedResourceModel resourceModel) throws HasthiException{
        if(managementEprOfResource.endsWith("//")){
            managementEprOfResource = managementEprOfResource.substring(0, managementEprOfResource.length()-1);
        }
        GetResourcePropertyDocumentResponseDocument response;
        try{
            //fetch the resource property document for given resource 
            NodeAddress address = new NodeAddress(managementEprOfResource);
            GetResourcePropertyDocumentDocument1 getResourcePropertyDocument = WsrfClientUtils.buildGetResourcePropertyDocumentRequest();
            MessageContext messageContext = new SimpleMessageContext( 
                    getResourcePropertyDocument, address.getAddressAsString(),
                    WsrfConstants.WSA_ACTION_GET_RESOURCE_PROPERTY_DOCUMENT);
            XmlObject responseMessage = container.sendReceive(messageContext);
            response = (GetResourcePropertyDocumentResponseDocument)responseMessage;
        }catch(HasthiException e){
            throw new HasthiException("Assigned Resource " + managementEprOfResource + " is Unavalible ", e,  
                    FaultCode.ErrorAtDependentService);
        }
        //Add the resource to resource model
        try {
            if(log.isTraceEnabled()){
                log.trace("Received :"+response);
            }
            return ResourceUtils.buildResourceFromPropertyDocument(response,resourceModel,managementEprOfResource);
        } catch (InvaliedResourceDataException e) {
            throw new HasthiError("Possible Error at Managment Agent",e);
        }
    }
    
    
    
    
    

//    /**
//     * Fetch a remote resource
//     * 
//     * @param resourceModelContext
//     * @param holderUrl
//     * @param resourceID
//     * @param parameterName
//     * @return
//     * @throws XmfException
//     */
//    public static Object fetchRemoteResourceParameter(ResourceModelContext resourceModelContext,
//            String holderUrl, QName resourceID, String parameterName) throws XmfException {
//        Map<QName, Object> remoteResourceParams = fetchRemoteResourceParameters(
//                resourceModelContext, holderUrl, resourceID);
//        return remoteResourceParams.get(parameterName);
//    }

    /**
     * 
     * @param resourceModelContext
     * @param holderUrl
     * @param resource
     * @return
     * @throws HasthiException
     */
    public static Map<QName, Object> fetchRemoteResourceParameters(
            ResourceModelContext resourceModelContext, String holderUrl, QName resource)
            throws HasthiException {
        UnicastContianier container = resourceModelContext.getContainer();
        GetResourcesDocument resourcesDocument = ManagerClientUtils.createGetResourcesRequest(
                new QName[] { resource }, false);
        MessageContext context = new SimpleMessageContext(resourcesDocument,holderUrl,
                GET_RESOURCES_ACTION);
        GetResourcesResponseDocument responseDocument = (GetResourcesResponseDocument) container
                .sendReceive(context);
        
        ManagedResourceType[] resources = responseDocument.getGetResourcesResponse().getResourceArray();
        if(resources != null && resources.length > 0 && resources[0] != null){
            Map<QName, Object> properties = XmlBeanUtils.extractProperties(resources[0]);
            return properties;
        }else{
            throw new HasthiException("Can not find Resource "+ resource , FaultCode.InvaliedLocalArgumnet);
        }
    }

    public static String fetchHolderURL(ResourceModelContext resourceModelContext,
            QName resourceName) throws HasthiException {
        GetResourceHoldersDocument getResourceHoldersDocument = GetResourceHoldersDocument.Factory
                .newInstance();
        GetResourceHolders resourceData = getResourceHoldersDocument.addNewGetResourceHolders();
        resourceData.addNewResourceName().setQNameValue(resourceName);

        UnicastContianier container = resourceModelContext.getContainer();
        MessageContext requestMessage = new SimpleMessageContext(getResourceHoldersDocument,resourceModelContext
                .getCoordinatorUrl(),
                GET_RESOURCES_HOLDER_ACTION);
        GetResourceHoldersResponseDocument responseDocument = (GetResourceHoldersResponseDocument) container
                .sendReceive(requestMessage);
        ManagerAddress[] resourceHolderArray = responseDocument.getGetResourceHoldersResponse().getResourceHolderArray();
        if(resourceHolderArray == null || resourceHolderArray.length == 0 || resourceHolderArray[0] == null){
            return null;
        }else{
            return resourceHolderArray[0].getSoapAddress();
        }
    }

    /**
     * Build a resource object using the Resource property document of the
     * managable resource
     * 
     * @param response
     * @param model
     * @param managmentEpr4Resource
     * @return
     * @throws HasthiException
     * @throws InvaliedResourceDataException 
     * @throws HasthiException 
     */
    public static ManagedResource buildResourceFromPropertyDocument(
            GetResourcePropertyDocumentResponseDocument response, MixedResourceModel model,
            String managmentEpr4Resource) throws InvaliedResourceDataException, HasthiException {
        XmlCursor c = response.getGetResourcePropertyDocumentResponse().newCursor();
        XmlObject resourceAsXml = (XmlObject) XmlBeanUtils.readValueOffXml(c,true);
        c.dispose();
        
        Map<QName, Object> extractedProperties = XmlBeanUtils.extractProperties(resourceAsXml);
        return model.createNewResource(extractedProperties, managmentEpr4Resource);
    }
    public static boolean isIncludedInSummerized(String name){
        return (RESOURCE_STATUS_PARAM.getLocalPart().equals(name) 
        || RESOURCE_CATEGORY_PARAM.getLocalPart().equals(name) 
        || RESOURCE_TYPE_PARAM.getLocalPart().equals(name) 
        || RESOURCE_STATUS_PARAM.getLocalPart().equals(name)
        || HOSTNAME_PARAM.getLocalPart().equals(name)
        || GROUP_PARAM.getLocalPart().equals(name));
    }
    
    public static int getIntProperty(ManagedResource resource,String name) throws HasthiException{
        String value = (String)resource.getProperty(name);
        if(value == null){
            return -1;
        }else{
            return Integer.parseInt(value);
        }
    }
    
    public static String getStringProperty(ManagedResource resource,String name) throws HasthiException{
        String value = (String)resource.getProperty(name);
        if(value == null){
            return "";
        }else{
            return value;
        }
    }
}
